DOM XSS in AngularJS expression with angle brackets and double quotes HTML-encoded
Ejecución de código vía directiva AngularJS ng-app cuando los angle brackets están codificados: el sandbox de AngularJS se elude con una expresión constructor.constructor('alert(1)')().
Target Overview & Vulnerability Summary
El laboratorio contiene una vulnerabilidad DOM XSS en la expresión AngularJS dentro de la funcionalidad de búsqueda. AngularJS escanea los nodos HTML que contienen la directiva ng-app y evalúa expresiones JavaScript encerradas en dobles llaves {{...}}. Este vector sigue siendo viable cuando los angle brackets (<, >) están codificados y el payload clásico <script> ya no aplica.
| Campo | Valor |
|---|---|
| Severidad | Media-Alta (ejecución de JavaScript en el contexto de la víctima) |
| Endpoint vulnerable | / (parámetro search reflejado en contexto AngularJS) |
| Root cause | La app carga AngularJS con ng-app y refleja el input dentro de una expresión evaluada por el framework |
Technical Breakdown & Exploitation Flow
1. Reconocimiento del contexto de renderizado
La página carga angular_1-7-7.js y declara ng-app en el body:
<script type="text/javascript" src="/resources/js/angular_1-7-7.js"></script>
<title>DOM XSS in AngularJS expression with angle brackets and double quotes HTML-encoded</title>
</head>
<body ng-app>
Al buscar, el parámetro se refleja con los angle brackets HTML-encoded:
<section class=blog-header>
<h1>0 search results for '<script>alert(1)</script>'</h1>
<hr>
</section>
2. Ejecución vía expresión AngularJS
Como la búsqueda se refleja dentro de una expresión {{...}} de AngularJS, no se necesita romper markup HTML: se inyecta una expresión que evade el sandbox del framework. El clásico {{constructor.constructor('alert(1)')()}} accede al constructor global Function desde el constructor de un objeto primitivo y lo invoca:
{{constructor.constructor('alert(1)')()}}
GET /?search={{constructor.constructor('alert(1)')()}} HTTP/2
Host: <LAB-ID>.web-security-academy.net
Al cargar la página, AngularJS evalúa la expresión y llama a alert(1).
Root Cause Analysis
El patrón defectuoso es confiar en la codificación HTML como única defensa. La codificación de < y > (y las comillas dobles) bloquea la inyección de markup clásica, pero no impide que la cadena llegue a un motor de plantillas del lado del cliente. La directiva ng-app convierte el texto reflejado en código evaluable: la combinación de (a) framework de templating activo en el DOM y (b) dato no sanitizado dentro de una expresión evaluada es el root cause.
El payload explota la cadena de prototipos de AngularJS: {{constructor}} devuelve el constructor del objeto, .constructor encadena hasta Function, y la invocación ('alert(1)')() ejecuta el código. Es un bypass del sandbox de expresiones de AngularJS 1.x (CSP no mitigado en este lab).
Secure Remediation
- No reflejar datos no confiables dentro de contextos evaluados por plantillas. En AngularJS, usar interpolación de datos
ng-bindo{{}}solo con datos ya sanitizados y no confiar en el sandbox para input atacante. - Deshabilitar la directiva
ng-appsobre nodos que rendericen parámetros del usuario, o migrar a un framework sin evaluación de expresiones (Angular 2+ sin{{}}en HTML generado). - Codificar al contexto correcto: dentro de una expresión de plantilla la codificación HTML no es suficiente; se requiere saneamiento previo y validación server-side del parámetro
search. - Como defensa adicional, aplicar CSP que restrinja
unsafe-eval(aunque AngularJS 1.x lo requiere para su funcionamiento, su presencia sin CSP limita el impacto de expresiones arbitrarias).